#include "stdafx.h"

#include "bochs.h"
#include "softfloatx80.h"

const floatx80 Const_QNaN = packFloatx80(0, floatx80_default_nan_exp, floatx80_default_nan_fraction);
const floatx80 Const_Z    = packFloatx80(0, 0x0000, 0);
const floatx80 Const_1    = packFloatx80(0, 0x3fff, IA32_CONST64(0x8000000000000000LL));
const floatx80 Const_L2T  = packFloatx80(0, 0x4000, IA32_CONST64(0xd49a784bcd1b8afeLL));
const floatx80 Const_L2E  = packFloatx80(0, 0x3fff, IA32_CONST64(0xb8aa3b295c17f0bcLL));
const floatx80 Const_PI   = packFloatx80(0, 0x4000, IA32_CONST64(0xc90fdaa22168c235LL));
const floatx80 Const_LG2  = packFloatx80(0, 0x3ffd, IA32_CONST64(0x9a209a84fbcff799LL));
const floatx80 Const_LN2  = packFloatx80(0, 0x3ffe, IA32_CONST64(0xb17217f7d1cf79acLL));
const floatx80 Const_INF  = packFloatx80(0, 0x7fff, IA32_CONST64(0x8000000000000000LL));

#define DOWN_OR_CHOP()  (FPU_CONTROL_WORD & FPU_CW_RC & FPU_RC_DOWN)

inline floatx80 FPU_round_const(const floatx80 &a, int adj)
{
  floatx80 result = a;
  result.fraction += adj;
  return result;
}


void IA32_CPU::FLDL2T(Ia32_Instruction_c *i)
{
   prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
       FPU_stack_overflow();
      return; 
  }

   the_i387.FPU_push();
  IA32_WRITE_FPU_REGISTER_AND_TAG(FPU_round_const(Const_L2T, 
	(FPU_CONTROL_WORD == FPU_RC_UP) ? 1 : 0), FPU_Tag_Valid, 0);
}

void IA32_CPU::FLDL2E(Ia32_Instruction_c *i)
{
   prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
       FPU_stack_overflow();
      return; 
  }

   the_i387.FPU_push();
  IA32_WRITE_FPU_REGISTER_AND_TAG(FPU_round_const(Const_L2E, DOWN_OR_CHOP() ? -1 : 0), FPU_Tag_Valid, 0);
}

void IA32_CPU::FLDPI(Ia32_Instruction_c *i)
{
   prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
       FPU_stack_overflow();
      return; 
  }

   the_i387.FPU_push();
  IA32_WRITE_FPU_REGISTER_AND_TAG(FPU_round_const(Const_PI, DOWN_OR_CHOP() ? -1 : 0), FPU_Tag_Valid, 0);
}

void IA32_CPU::FLDLG2(Ia32_Instruction_c *i)
{
   prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
       FPU_stack_overflow();
      return; 
  }

   the_i387.FPU_push();
  IA32_WRITE_FPU_REGISTER_AND_TAG(FPU_round_const(Const_LG2, DOWN_OR_CHOP() ? -1 : 0), FPU_Tag_Valid, 0);
}

void IA32_CPU::FLDLN2(Ia32_Instruction_c *i)
{
   prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
       FPU_stack_overflow();
      return; 
  }

   the_i387.FPU_push();
  IA32_WRITE_FPU_REGISTER_AND_TAG(FPU_round_const(Const_LN2, DOWN_OR_CHOP() ? -1 : 0), FPU_Tag_Valid, 0);
}

void IA32_CPU::FLD1(Ia32_Instruction_c *i) 
{
   prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
       FPU_stack_overflow();
      return; 
  }

   the_i387.FPU_push();
  IA32_WRITE_FPU_REGISTER_AND_TAG(Const_1, FPU_Tag_Valid, 0);
}

void IA32_CPU::FLDZ(Ia32_Instruction_c *i)                      
{
   prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
       FPU_stack_overflow();
      return; 
  }

   the_i387.FPU_push();
  IA32_WRITE_FPU_REGISTER_AND_TAG(Const_Z, FPU_Tag_Zero, 0);
}
